vagrant box add jenkins-lab-demo http://bit.ly/2BxqFPTÉcole Nationale des Sciences Géographiques
Décembre 2017 - Damien DUPORTAL
This work is licensed under a http://creativecommons.org/licenses/by/4.0/
Training Engineer @ CloudBees
Docker & Apple fanboy.
Human stack focused
Rock climber
Contact:
Twitter: @DamienDuportal
Github: dduportal
eMail: damien.duportal@gmail.com
TBD.
TBD.
"Gestion de Code Source"
Les Gestionnaires de Code Source, également connus comme "Version Control Systems" (VCS):
Sont des systèmes logiciels
Conservent toutes les modifications apportées à une collection de fichiers, dans le temps
Permettent de partager ces changements
Fournissent des fonctionnalités de merge et de suivi des modifications
Pour collaborer efficacement sur un même référentiel de code source
Aide à la résolution de conflits
Partage de contenu facile
Pour conserver une trace de tous les changements : On parle de source unique de vérité (Single Source of Truth)
Historique complet des modifications
Possibilité de retour arrière à tout moment
Locaux
Centralisés
Distribués
Plus vieux type, ancêtre de tous les autres
Uniquement historique de modification
Utilise une "base de donnée de versions" des fichiers
Stockage uniquement des différences ("diff")
Pas de partage
Exemple: rcs (toujours dans Apple XCode Tools)
Couvre historique ET partage
La "base de données de versions" est stockée sur un serveur central
Chaque client ne possède qu'une seule version du code
Apprentissage très facile, limité sur la résolution de conflits
Exemples: CVS, SVN, Perforce, TFS
La "base de données de versions" est distribuée par duplication sur chaque noeud
Exemples: Git, Mercurial, Bazaar, Monotone
Hébergés dans le Cloud
Hébergé "à la maison"
SCM as a Service
Le serveur centralisé est un service hébergé par un fournisseur
Avantages:
Pas de temps/énergie passés sur la gestion
Associent au SCM d’autre services : gestionnaire de tickets, wiki, éditeur de texte online, etc.
Risque: Votre code est hébergé par un tiers
Exemples: GitHub, Bitbucket by Atlassian, Amazon CodeCommit, Visual Studio Online by Microsoft, SourceForge, GitLab.com, etc.
Pour pallier au risque précédent, on trouve des versions "On-Premide" (généralement payantes)
Le monde de l’Open Source fourni également des solutions à héberger soit-même
Très souvent gratuit et on peut le corriger
Temps et énergie à consacrer
Exemples: Gitlab, Gitea, Gogs, Bazaar server, VisualSVN Server, etc.
diff: un ensemble de lignes "changées" sur un fichier donné
changeset: un ensemble de "diff" (donc peut couvrir plusieurs fichiers)
commit: Action de sauvegarder un changeset dans la base de données des versions.
Le dernier commit dans l’historique est aliasé comme "HEAD"
Abstraction d’une version "isolée" du code
Concrètement, une branche est un alias pointant vers un "commit"
On intègre une branche dans une autre en effectuant un merge
Un nouveau commit est créé, fruit de la combinaison de 2 autres commits
Une Pull Request (ou "Merge Request") est une procédure de revue de code avant intégration
Voici quelques motifs d’utilisation des SCMs :
"Centralized" Flow
"Feature Branch" Flow
"Git" Flow
"GitHub" Flow
Une seule branche par fonctionnalité
"Infrastructure as Code" :
Besoins de traçabilité, de définition explicite et de gestion de conflits
Collaboration requise pour chaque changement (revue, responsabilités)
Code Civil:
Un peu de lecture :
Le code est donc sujet à erreurs: Conséquences?
Les tests identifient ces erreurs, dans un but de correction
Le test logiciel est une pratique suivant 2 piliers :
Valider que le logiciel remplisse les rôles qui lui sont confiés
Rechercher les fautes pour les corriger, améliorant la qualité du système
Automatiser : répétition et reproductibilité
Test Manuel à considérer dans peu de cas, quand :
Coût de l’automatisation dépasse sa valeur
Automatisation impossible
SUT: "System Under Testing". Défini les frontières du système.
Test Double: Terme générique désignant un sous-ensemble simplifié du "S.U.T.". Exemples: Mock, Stub, Spy, etc.
Boîte Blanche: Tester avec une vue interne du SUT
Boîte Noire: Tester le SUT sans connaissance préalable de ses mécanismes interne
La question primordiale est: "Que voulez-vous tester ?"
En fonction de la réponse, différent types de tests peuvent être utilisé (liste NON exhaustive) :
Unit testing
Integration testing
Smoke testing
Functional Testing
Non-Regression testing
Acceptance testing
Focalisé sur le plus petit sous sytème possible du SUT, en "boîte blanche"
Tests indépendants les uns des autres
Ordre d’exécution non important
Utilisation de Test Doubles pour simuler le "reste" en bon fonctionnement
Vérifier l’intégration entre différents sous-systèmes
Le SUT est en "boîte blanche"
But : Fail Fast en "boîte blanche"
Valide les fonctions "de base" du système
On parle parfois de "Sanity Checking"
If it smokes, it’s bad
Vérifie que le logiciel se comporte comme prévue par les personnes en charge de la fabrication
Pas de biais d’inteprétation
Le SUT est en "boîte noire"
Vérifie que le SUT a un comportement stable dans le temps
Focalisation sur bug qui ne doit pas revenir
Le SUT est en "boîte noire"
Correcting a single bug may introduce several more.
Également connu sous l’acronyme "UAT" User Acceptance Testing
Vérifie que le logiciel se comporte comme attendu par l’utilisateur
Biais de communication inclus
Le SUT est en "boîte noire"
Fonction des temps d’exécutions, des coûts de corrections, et des valeurs ajoutées. Contextuel.
TDD: Écrire les tests unitaires avant le code
BDD: Privilégier language naturel et interactions
"Given, When, Then"
Moins de technique. Valeur ajoutée pour l’utilisateur.
Continuous Integration is a software development practice where members of a team integrate their work frequently. Usually each person integrates at least daily - leading to multiple integrations per day.
Construire et intégrer le code en continu
Le code est intégré souvent, au moins quotidiennement pour que l’intégration soit un non-évenement
Chaque intégration est validée par une construction automatisée avec tests
But : Détecter les fautes au plus tôt
Continuous Integration doesn’t get rid of bugs, but it does make them dramatically easier to find and remove.
Continous Delivery (CD)
Diminuer les risque liés au déploiement
Permettre de récolter des retours utilisateurs plus souvent
Rendre l’avancement visible par tous
How long would it take to your organization to deploy a change that involves just one single line of code?
Suite logique de l’intégration continue:
Chaque changement est potentiellement déployable en production
Le déploiement peut donc être effectué à tout moment
Your team prioritizes keeping the software deployable over working on new features
Continuous Deployment
Version "avancée" de la livraison continue:
Chaque changement est déployé en production, de manière automatique
Question importante: En avez-vous besoin ?
Avez-vous les mêmes besoin que Amazon Google ou Netflix ?
"Software Supply Chain"
"Feedback loop" / "Boucle de feedback"
Problèmatique : réagir rapidement pour corriger une faute
"Au plus tôt, au moins cher"
Problème #1: Avoir un retour
Problème #2: Réagir systématiquement sur un retour
Problème #3: Avoir confiance
Quels acteurs du système ?
Quel médium de communication ?
Quel déclencheurs et quelles limites ?
Culture à construire, les outils suivent facilement
Industrialisation du logiciel
Modélisation de la chaîne de valeur ("Value Stream Mapping")
"Fast is cheap": Piloté par le concept de la défaillance rapide ("fail fast")
Stage ("étape"): Élément de base
Abstraction atomiques d’un ensemble d’actions
Exemple: "Build", "Run Unit Tests"
Possibilité de parallèlisation
Gate ("Porte"): Transition entre 2 étapes
Manuel ou automatique
Peuvent être conditionnelles
Déclenchement initial : un changement dans la base de code
Chaque étape peut produire des livrables: on parlera d'Artefacts dans ce cours
Le déploiement est ce qui permet de rendre le logiciel prêt à l’usage
Un "déploiement" est exécuté vers un environnement
Production
Préproduction ("staging") / recette ("qualification")
Tests
"Disaster Recovery Environment"
Commencer par un "Produit Minimum Viable" (MVP) puis itérer
S’efforcer d’appliquer les bonne pratiques
Optimiser le Pipeline (lors des itérations)
Réutilisation des artefacts: "Only Build Your Binaries Once"
Arrêt du Pipeline dès qu’une faute est identifiée: "Fail Fast"
Identifier si un artefacts n’est pas déployable (tests…)
S’assurer qu’une même version de la base de code est utilisée à tout moment pour un Pipeline donnée
Paralléliser les étapes
Arrêt du Pipeline si une "branche" est en erreur
Sinon: étape inutile à supprimer
Les "gates" manuelles peuvent également être paralleliser
relation "1-N": N "gates" manuelles déclencheront N étapes parallèles
Un peu de lecture :
Votre organisation utilise l'information pour créer de la valeur
L’information doit donc être:
Confidentielle
Intègre
Disponible
C’est l’ensemble des pratiques et des outils permettant de prévenir et combattre les menaces sur l’organisation
4 piliers:
Connaissance du sytème
Least Privilege
Défense en profondeur
Mieux vaut prévenir que guérir
AAA signifie :
Authentification
Authorisation
Accounting (comptabilisation)
C’est l’ensemble des procédures et outils pour identifier un acteur avec une confiance suffisante
Une fois l’acteur identifié avec confiance, il faut contrôler ses droit en terme de manipulations
Nomenclature :
Ressources: Tâches ou objets manipulables et accessibles
Rôles: Ensemble de droits regroupés par commodité
Requêteurs: Acteur souhaitant manipuler des ressources
Etre autorisé à manipuler des ressources ne garantie pas l’effection à 100%
Limites du système (mémoire, disque, consommation, temps, etc.)
Erreurs, pannes et fautes
L'"accounting" permet de mesurer et contrôler les manipulations
Respect des limites
Reprises sur erreur
Capacity planning
Un peu de lecture :
VirtualBox (5.1.30+)
Check: VboxManage -v
Vagrant (2.0.1+)
Check: vagrant -v
Pour le proxy HTTP:
https://github.com/tmatilai/vagrant-proxyconf
export VAGRANT_HTTP_PROXY=… && vagrant …
et/ou https://github.com/AlbanMontaigu/docker-transparent-proxy
vagrant box add jenkins-lab-demo http://bit.ly/2BxqFPTCréer un dossier de travail nommé jenkins-lab-demo
dans votre HOME utilisateur
Se positionner dans ce dossier
Exécuter vagrant init
mkdir ~/jenkins-lab-demo
cd ~/jenkins-lab-demo
vagrant init -m -f jenkins-lab-demovagrant up # Démarrer la VM
vagrant suspend # Suspendre la VM
vagrant resume # Relancer la VM
vagrant halt # Arrêter "proprement la VM"
vagrant destroy # Détruire la VM (BRUTAL)Dans votre navigateur, ouvrir http://localhost:10000
Bienvenue sur la page d’accueil du Lab:
Le lien Workshop Slides vous permettra d’accéder au slides
Cliquer sur le lien Git Server sur la page d’accueil du Lab
S’authentifier en tant que butler (mot de passe butler)
Cliquer sur Explore (en haut)
Cliquer sur butler/demoapp
But : Illustrer un exemple de "Software Supply Chain"
Problématique : Quel language/framewor/outil choisir ?
Solution:
"Opinionated" demo application
Tout le monde sur le même pied
Application Web
Page d’accueil affichant "Greetings from Spring Boot!"
C’est un des exemples de Spring Boot Starter
Langage: Java (OpenJDK 8)
Toolchain: Maven (Maven >= 3.3)
Code source stocké dans un dépôt Git
Configuration Maven: pom.xml
Code source de l’application: src/main/java/
Code source des tests: src/test
Script utilitaires: scripts
Ouvrir la console DevBox
WebSockets doit être autorisé
Clean the window: clear
Show command history: history
CTRL + R: search the command history interactively
CTRL + C: cancel current command and clean line buffer
CTRL + A: jump to beginning of line
CTRL + E: jump to end of line
cat (concatenate)
ls (list)
cd (change directory)
pwd (print working directory)
man (manual)
rm (remove)
mkdir (make directory)
touch (create an empty file)
Obtenir l’adresse HTTP du dépôt depuis le GitServer
# Get the git repository
git clone http://localhost:10000/gitserver/butler/demoapp
# Browse to the local repository
cd ./demoapp
# Check source code
ls -lMaven TL;DR:
Workflow standardisé
pom.xml décrit l’application (Project Object Model)
Maven Command line : mvn, attends des goals en argument
mvn dependency:listAccepte des flags
mvn dependency:list -fnGoal compile
Résolution des dépendances
Pré-traitement du code source
Compilation des classes
Résultats dans le dossier ./target:
mvn compile
ls -l ./targetGoal test
Exécute le goal compile
Compilation des tests unitaires
Exécution des tests unitaires
Rapports de tests dans ./target/surefire-reports :
mvn test
ls -l ./target/surefire-reportsgoal package
Exécute les goals compile et test
Paquetage de l’application
Résultat dans ./target
mvn package
ls -lrh ./target/Spring Boot demo exécutée comme un "Über-Jar"
Exécution avec la commande java:
java -jar ./target/demoapp-1.0.0.jarOuvrir une autre instance de DevBox et vérifier
http//localhost:8080 avec curl
Goal verify
Exécute compile, test et package
Compile et exécute les tests d’intégration sur l’application empaquetée
Rapport de tests dans ./target/failsafe-reports:
mvn verify # 1 test failure expected
ls -l ./target/failsafe-reportsDéfinissons ensemble un pipeline
Etudier le contenu du dossier scripts
Logiciel Open Source
Orchestrateur de tâches
Un des tout premiers moteur d’intégration continue
Architecture centrée sur les plugins
Un gigantesque écosystème
Pierre angulaire de l’évolution de Jenkins
Visualisation et manipulation de "Pipelines"
GUI moderne, se concentrant sur les actions principales
Un outil pour définir votre flux de Continuous Delivery/Deployment avec votre code
!= outil de création de job comme "Job DSL"
Réduit le nombre de jobs nécessaires
Spécification facilitée par du "code"
Survi au redémarrage du Jenkins Master
Le Pipeline est décrit dans un fichier texte: le JenkinsFile
DSL spécifique
stocké dans un SCM
versionné
isolation par branche
suit les patterns à la “Git / Github / Gitlab flow”
Pipeline-as-code: Nous avons besoin d’un Jenkinsfile
Par où commencer ?
Declarative
Syntaxe par défaut
S’utilise avec Blue Ocean
Scripted
Syntaxe originale (~3 ans)
"Great Power == Great Responsibility"
À utiliser lorsque le Déclaratif commence à être bizarre
Fourni le cycle ("round trip") complet avec le SCM
Pas de Pipeline ? "Suivez le guide".
Le Pipeline existe déjà ? Edit, commit, et exécutez le
Access your Jenkins instance:
Log in as the user butler (password is the same)
This is the "Jenkins Classic GUI"
Switch to Blue Ocean:
Or click on the item "Open Blue Ocean", on the left menu
Create a new Pipeline, with the following properties:
Stored in Git
Get the SSH URL from the git server
Configure Jenkins access to the source code:
In Gitea, click the top-right user drop down
Browse to SSH/GPG Keys
Add a new key, by copy and pasting from Jenkins
Click the button Create a Pipeline
Use the Blue Ocean Pipeline Editor and Gitea git server
Create a Pipeline that have 3 stages: Build, Test and Deploy
Each stage has 1 step that prints a message
"Building…" for Build, "Testing…" for Test …
Save, add a commit message and see the build kicking off
pipeline {
agent any
stages {
stage('Build') {
steps {
echo 'Build'
}
}
stage('Test') {
steps {
echo 'Test'
}
}
stage('Deploy') {
steps {
echo 'Deploy'
}
}
}
}Using the Blue Ocean Pipeline Editor:
Edit the current Pipeline’s 3 stages to run scripts
Scripts are stored in the ./scripts folder (in SCM)
Use the step Shell Script (keyword sh)
Remove the echo steps
Save, add a commit message and see the build kicking off
pipeline {
agent any
stages {
stage('Build') {
steps {
sh './scripts/build.sh'
}
}
stage('Test') {
steps {
sh './scripts/test.sh'
}
}
stage('Deploy') {
steps {
sh './scripts/deploy.sh'
}
}
}
}Using the Blue Ocean Pipeline Editor:
Edit the current Pipeline
Build stage should archive all *.jar files
Found in the directory target. TIP for pattern: *.jar
Test stage should publish the junit test reports
Found in target. TIP for recursive pattern: **/*.xml
Save, add a commit message and see the build kicking off
Build should be UNSTABLE
pipeline {
agent any
stages {
stage('Build') {
steps {
sh './scripts/build.sh'
archiveArtifacts 'target/*.jar'
}
}
stage('Test') {
steps {
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
stage('Deploy') {
steps {
sh './scripts/deploy.sh'
}
}
}
}Le build est en état UNSTABLE (jaune)
Priorité: réparer le build
Utiliser Gitea git server
Les tests d’intégration sont dans src/test/java/hello
Indices:
Integration Tests: == IT
Il suffit de savoir commenter/dé-commenter
Depuis src/test/java/hello/HelloControllerIT.java
Cliquer sur "Edit"
Commenter la ligne 39
Dé-commenter la ligne 40
Commit avec un message (push automatique)
Lancer le build manuellement dans Blue Ocean
Le build doit être vert (Stable)
Nous avons dû lancer le build manuellement
IC: Retours rapides !
Lancer le build dès que le code est poussé
Configurons un "Webhook" :
Depuis Gitea git server → Settings → Webhooks
Ajouter un nouveau webhook:
Type: Gitea
When should this webhook be triggered?: I need everything
Payload URL: http://localhost:10000/jenkins/job/demoapp/build?delay=0
Ajoutez un commentaire dans le Jenkinsfile depuis Gitea git server
Un build va démarrer
Validez dans l’onglet "Changes"
Dans l’éditeur Blue Ocean, voir la version textuelle:
Combinaison CTRL + S (On Mac: CMD +S)
Bi-directionnel: essayez de charger une solution de pipeline
Le Pipeline Syntax Snippet Generator comme acolyte:
Génération dynamique en fonction de vos plugins
Depuis l’interface "ancienne" de Jenkins
Menu de gauche de votre job "Pipeline" (ou MultiBranch)
But: réutiliser les binaires générés dans Build
Action: "mise sur étagère": Stash / Unstash
Modifier le Pipeline pour :
"Stasher" le dossier target, à la fin de la phase Build
"Unstasher" au début de la phase Test
Attention, une limite de l’éditeur Blue Ocean va être atteinte
L’éditeur Blue Ocean ne supporte pas encore le ré-ordonnancement de "stages"
Mode textuel et/ou Snippet Generator à utiliser
pipeline {
agent any
stages {
stage('Build') {
steps {
sh './scripts/build.sh'
archiveArtifacts 'target/*.jar'
stash(name: 'build-result', includes: 'target/**/*')
}
}
stage('Test') {
steps {
unstash 'build-result'
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
stage('Deploy') {
steps {
sh './scripts/deploy.sh'
}
}
}
}Section post :
Contient des "steps" à exécuter à la fin du Pipeline ou après une "stage"
Divisé en "condition d’états":
always, success, failure, changed
Chaque condition contient ses propres "steps"
Pas encore intégré dans l’éditeur Blue Ocean
Si le "stage" Build échoue, alors la tâche "archiveArtifacts" ne devrait pas être exécutée
Même chose pour stash
Les rapports de tests unitaires doivent être publiés dans tous les cas après la phase Build
Format Junit
Stockés dans target/**/*.xml
Utiliser la documentation:
pipeline {
agent any
stages {
stage('Build') {
steps {
sh './scripts/build.sh'
}
post {
success {
archiveArtifacts 'target/*.jar'
stash(name: 'build-result', includes: 'target/**/*')
}
always {
junit 'target/**/*.xml'
}
}
}
stage('Test') {
steps {
unstash 'build-result'
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
stage('Deploy') {
steps {
sh './scripts/deploy.sh'
}
}
}
}Un noeud (ou node) est une machine prête à recevoir des builds
Step agent spécifie sur quel "noeud" exécuter des "stages".
Une section agent globale doit être définie
(au niveau du block pipeline)
On peut aussi définire des sections agent par "stage"
Exécuter l’étape Build sur un agent
configuré avec le label maven-jdk8
Exécuter l’étape Test sur un agent
configuré avec le label java8
L’éditeur Blue Ocean est utilisable
pipeline {
agent any
stages {
stage('Build') {
agent {
node {
label 'maven-java8'
}
}
steps {
sh './scripts/build.sh'
}
post {
always {
junit 'target/**/*.xml'
}
success {
archiveArtifacts 'target/*.jar'
stash(name: 'build-result', includes: 'target/**/*')
}
}
}
stage('Test') {
agent {
node {
label 'java8'
}
}
steps {
unstash 'build-result'
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
stage('Deploy') {
steps {
sh './scripts/deploy.sh'
}
}
}
}But: Tester en parallèle l’application sur java 7 et 8
Mot clef parallel définissant un block contenant
des "stages"
Agent java7 pour le Test Java 7
L’éditeur Blue Ocean est utilisable (et recommandé)
pipeline {
agent any
stages {
stage('Build') {
agent {
node {
label 'maven-java8'
}
}
steps {
sh './scripts/build.sh'
}
post {
always {
junit 'target/**/*.xml'
}
success {
archiveArtifacts 'target/*.jar'
stash(name: 'build-result', includes: 'target/**/*')
}
}
}
stage('Test') {
parallel {
stage('Test Java 8') {
agent {
node {
label 'java8'
}
}
steps {
unstash 'build-result'
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
stage('Test Java 7') {
agent {
node {
label 'java7'
}
}
steps {
unstash 'build-result'
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
}
}
stage('Deploy') {
steps {
sh './scripts/deploy.sh'
}
}
}
}But: Usage de Docker pour faciliter la définition des environements de build
Le mot clef agent permet d’exécuter les "stages" dans
un container Docker, depuis une "image Docker",
ou depuis un Dockerfile (recette maison d’image Docker)
Exécuter le Build dans un containeur
basé sur le fichier Dockerfile.build
Exécuter le Test Java 8 dans un containeur
basé sur les images maven:3-jdk-8-alpine
Trick: documentation manquante sur filename,
dans un block dockerfile
pipeline {
agent any
stages {
stage('Build') {
agent {
dockerfile {
filename 'Dockerfile.build'
label 'docker'
}
}
steps {
sh './scripts/build.sh'
}
post {
always {
junit 'target/**/*.xml'
}
success {
archiveArtifacts 'target/*.jar'
stash(name: 'build-result', includes: 'target/**/*')
}
}
}
stage('Test') {
parallel {
stage('Test Java 8') {
agent {
docker {
image 'maven:3-jdk-8-alpine'
label 'docker'
}
}
steps {
unstash 'build-result'
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
stage('Test Java 7') {
agent {
node {
label 'java7'
}
}
steps {
unstash 'build-result'
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
}
}
stage('Deploy') {
steps {
sh './scripts/deploy.sh'
}
}
}
}Jenkins permet de "mettre en pause" l’exécution d’un pipeline, en attendant une validation humaine
Continuous Delivery / Deployment
Mot-clef input, c’est une "step" Pipeline
Hautement configurable: Documentation Step Input
Généralement utilisé dans un "stage" dédié.
Obligatoirement avec agent none (pas d’exécuteur, pas de workspace)
Ajouter une stage "approval" avant le déploiement
pipeline {
agent any
stages {
stage('Build') {
agent {
dockerfile {
filename 'Dockerfile.build'
label 'docker'
}
}
steps {
sh './scripts/build.sh'
}
post {
always {
junit 'target/**/*.xml'
}
success {
archiveArtifacts 'target/*.jar'
stash(name: 'build-result', includes: 'target/**/*')
}
}
}
stage('Test') {
parallel {
stage('Test Java 8') {
agent {
docker {
image 'maven:3-jdk-8-alpine'
label 'docker'
}
}
steps {
unstash 'build-result'
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
stage('Test Java 7') {
agent {
node {
label 'java7'
}
}
steps {
unstash 'build-result'
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
}
}
stage('Approval') {
agent none
steps {
input(message: 'Deploy Application?', ok: 'Yes Deploy!')
}
}
stage('Deploy') {
steps {
sh './scripts/deploy.sh'
}
}
}
}Définir l’exécution conditionnelle d’une "stage"
Mot clef when
Doit contenir au moins une condition parmi:
branch
environment
expression
Logique "built-in": allOf, anyOf, etc.
Définir des collections de clé-valeurs, en tant que variables d’environement:
Définition globale ou par "stage"
Ou en utilisant withEnv dans un block steps
pour une instruction spécifique
N’éxecuter les "stages" Approval et Deploy que:
Si on se trouve sur la branche master
Ou si la variable FORCE_DEPLOY est à true
pipeline {
agent any
environment {
FORCE_DEPLOY = 'false'
}
stages {
stage('Build') {
agent {
dockerfile {
filename 'Dockerfile.build'
label 'docker'
}
}
steps {
sh './scripts/build.sh'
}
post {
always {
junit 'target/**/*.xml'
}
success {
archiveArtifacts 'target/*.jar'
stash(name: 'build-result', includes: 'target/**/*')
}
}
}
stage('Test') {
parallel {
stage('Test Java 8') {
agent {
docker {
image 'maven:3-jdk-8-alpine'
label 'docker'
}
}
steps {
unstash 'build-result'
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
stage('Test Java 7') {
agent {
node {
label 'java7'
}
}
steps {
unstash 'build-result'
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
}
}
stage('Approval') {
agent none
steps {
input(message: 'Deploy Application?', ok: 'Yes Deploy!')
}
when {
anyOf {
branch 'master'
environment name: 'FORCE_DEPLOY', value: 'true'
}
}
}
stage('Deploy') {
steps {
sh './scripts/deploy.sh'
}
when {
anyOf {
branch 'master'
environment name: 'FORCE_DEPLOY', value: 'true'
}
}
}
}
}Directive parameters : l’utilisateur fournit des argument
au pipeline
Disponible en tant que variables accessibles dans l’objet params
Oeuf & Poule : Jenkins ne peut accéder au paramètre lors dur 1er build
Ajouter un paramètre DEPLOY_MESSAGE
dont la valeur par défaut est Deploy ?
Ce paramètre est utilisé dans le input
pipeline {
agent any
parameters {
string(name: 'DEPLOY_MESSAGE', defaultValue: 'Deploy ?', description: 'Message de déploiement')
}
environment {
FORCE_DEPLOY = 'false'
}
stages {
stage('Build') {
agent {
dockerfile {
filename 'Dockerfile.build'
label 'docker'
}
}
steps {
sh './scripts/build.sh'
}
post {
always {
junit 'target/**/*.xml'
}
success {
archiveArtifacts 'target/*.jar'
stash(name: 'build-result', includes: 'target/**/*')
}
}
}
stage('Test') {
parallel {
stage('Test Java 8') {
agent {
docker {
image 'maven:3-jdk-8-alpine'
label 'docker'
}
}
steps {
unstash 'build-result'
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
stage('Test Java 7') {
agent {
node {
label 'java7'
}
}
steps {
unstash 'build-result'
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
}
}
stage('Approval') {
agent none
steps {
input(message: params.DEPLOY_MESSAGE, ok: 'Yes Deploy!')
}
when {
anyOf {
branch 'master'
environment name: 'FORCE_DEPLOY', value: 'true'
}
}
}
stage('Deploy') {
steps {
sh './scripts/deploy.sh'
}
when {
anyOf {
branch 'master'
environment name: 'FORCE_DEPLOY', value: 'true'
}
}
}
}
}Options: Configurer un "job" depuis le Pipeline
Configuration: Même chose dans la GUI "Legacy"
Mot clef options
Documentation des options: https://jenkins.io/doc/book/pipeline/syntax/#options
Certaines options comme timeout peuvent être appliquée
dans un bloc step
On souhaite que la "stage" Approval attende 3 minute avant d’arrêter le pipeline
On ne veut conserver que les 5 derniers builds d’un pipeline: limiter l’usage disque
pipeline {
agent any
options {
buildDiscarder(logRotator(numToKeepStr: '5'))
}
parameters {
string(name: 'DEPLOY_MESSAGE', defaultValue: 'Deploy ?', description: 'Message de déploiement')
}
environment {
FORCE_DEPLOY = 'false'
}
stages {
stage('Build') {
agent {
dockerfile {
filename 'Dockerfile.build'
label 'docker'
}
}
steps {
sh './scripts/build.sh'
}
post {
always {
junit 'target/**/*.xml'
}
success {
archiveArtifacts 'target/*.jar'
stash(name: 'build-result', includes: 'target/**/*')
}
}
}
stage('Test') {
parallel {
stage('Test Java 8') {
agent {
docker {
image 'maven:3-jdk-8-alpine'
label 'docker'
}
}
steps {
unstash 'build-result'
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
stage('Test Java 7') {
agent {
node {
label 'java7'
}
}
steps {
unstash 'build-result'
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
}
}
stage('Approval') {
agent none
steps {
timeout(time: 3, unit: 'MINUTES') {
input(message: params.DEPLOY_MESSAGE, ok: 'Yes Deploy!')
}
}
when {
anyOf {
branch 'master'
environment name: 'FORCE_DEPLOY', value: 'true'
}
}
}
stage('Deploy') {
steps {
sh './scripts/deploy.sh'
}
when {
anyOf {
branch 'master'
environment name: 'FORCE_DEPLOY', value: 'true'
}
}
}
}
}Create a repository jenkins-libs
Init with a file vars/runPipeline.groovy:
def call(String MESSAGE) {
echo "Lib: ${MESSAGE}"
}Switch to legacy UI, configure the Multibranch job
Add the shared library
Adapt the pipeline to run the function in Build stage
pipeline {
agent any
libraries {
lib('jenkins-libs@master')
}
options {
buildDiscarder(logRotator(numToKeepStr: '5'))
}
parameters {
string(name: 'DEPLOY_MESSAGE', defaultValue: 'Deploy ?', description: 'Message de déploiement')
}
environment {
FORCE_DEPLOY = 'false'
}
stages {
stage('Build') {
agent {
dockerfile {
filename 'Dockerfile.build'
label 'docker'
}
}
steps {
runPipeline('Salut')
sh './scripts/build.sh'
}
post {
always {
junit 'target/**/*.xml'
}
success {
archiveArtifacts 'target/*.jar'
stash(name: 'build-result', includes: 'target/**/*')
}
}
}
stage('Test') {
parallel {
stage('Test Java 8') {
agent {
docker {
image 'maven:3-jdk-8-alpine'
label 'docker'
}
}
steps {
unstash 'build-result'
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
stage('Test Java 7') {
agent {
node {
label 'java7'
}
}
steps {
unstash 'build-result'
sh './scripts/test.sh'
junit 'target/**/*.xml'
}
}
}
}
stage('Approval') {
agent none
steps {
timeout(time: 3, unit: 'MINUTES') {
input(message: params.DEPLOY_MESSAGE, ok: 'Yes Deploy!')
}
}
when {
anyOf {
branch 'master'
environment name: 'FORCE_DEPLOY', value: 'true'
}
}
}
stage('Deploy') {
steps {
sh './scripts/deploy.sh'
}
when {
anyOf {
branch 'master'
environment name: 'FORCE_DEPLOY', value: 'true'
}
}
}
}
}